﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;

using System.IO;
using CompileEffect;
using XnaColor = Microsoft.Xna.Framework.Color;  
using WinColor = System.Drawing.Color;
using WinPoint = System.Drawing.Point;
using WinRect = System.Drawing.Rectangle;
using WinFont = System.Drawing.Font;
using GraphicsUnit = System.Drawing.GraphicsUnit;
using WinSize = System.Drawing.Size;
using MapBase = JYoperation.Class.JYcore.MapBase;
using System.Collections;
using System.Runtime.InteropServices;
using KGFontOpr;

using JYoperation.Class; 

namespace Candy
{
    public enum BlendMode
    {
        /// <summary>
        /// 不透明
        /// </summary>
        NoAlpha = 0,
        /// <summary>
        /// 按照实际透明度
        /// </summary>
        RealAlpha = 1,
        /// <summary>
        /// 乘法，纹理RGB分别乘以背景色的RGB，A等于纹理A
        /// </summary>
        Multi = 2,
        /// <summary>
        /// 滤色，纹理RGB分别乘以背景色的RGB，A等于纹理A
        /// </summary>
        Filter = 4,
    }
    public class RenderMgr
    {
        static float[] TempX = new float[4];
        static float[] TempY = new float[4];
        static float[] TempZ = new float[4];
        static public bool IsDrawnBuffer = false;
        /// <summary>
        /// 每批次最大渲染数
        /// </summary>
        public const int MaxRenderCount = 5000;
        /// <summary>
        /// 自定义顶点格式
        /// </summary>
        public struct MyVertex
        {
            public Vector4 Position;
            public Vector2 TextureCoordinate;
            public float Alpha;
            public float UseTransparent;
            public XnaColor BackColor;
        }
        /// <summary>
        /// 顶点声明
        /// </summary>
        static public VertexDeclaration vertexdec = new VertexDeclaration(
            new VertexElement(0, VertexElementFormat.Vector4, VertexElementUsage.Position, 0),
            new VertexElement(16, VertexElementFormat.Vector2, VertexElementUsage.TextureCoordinate, 0),
            new VertexElement(24, VertexElementFormat.Vector2, VertexElementUsage.Color, 0),
            new VertexElement(32, VertexElementFormat.Color, VertexElementUsage.Color, 1));
        /// <summary>
        /// 顶点数组
        /// </summary>
        static public MyVertex[] VertexBuf = new MyVertex[MaxRenderCount * 4];
        /// <summary>
        /// 顶点索引
        /// </summary>
        static public short[] VertexIdx = new short[MaxRenderCount * 6];
        /// <summary>
        /// 渲染数量
        /// </summary>
        static public int RenderCount = 0;
        /// <summary>
        /// 当前纹理
        /// </summary>
        static public Texture2D CurTex = null;
        static Rectangle BufRect;
        static public void Init(Rectangle rect,GraphicsDevice xnaDevice, WinFont winfont)
        {
            GlobalFont = new FontOpr(xnaDevice, winfont);
            BufRect = rect;
            short n = 0;
            for (short i = 0; i < MaxRenderCount; i++)
            {
                VertexIdx[i * 6] = n;
                VertexIdx[i * 6 + 1] = (short)(n + 1);
                VertexIdx[i * 6 + 2] = (short)(n + 2);
                VertexIdx[i * 6 + 3] = (short)(n + 2);
                VertexIdx[i * 6 + 4] = (short)(n + 3);
                VertexIdx[i * 6 + 5] = n;
                n += 4;
            }


        }

        /// <summary>
        /// 将Pic画到当前RenderTarget
        /// </summary>
        /// <param name="Pic">要画的Pic</param>
        /// <param name="Pos">绘画的位置</param> 
        /// <param name="alpha">透明度</param>
        /// <param name="srcRect">要画的原图的区域</param> 
        /// <param name="destRect">要画成的大小</param>  
        static public void DrawPic(
            Texture2D Pic,
            Vector3 Pos,
            Vector4[] srcRect,
            Vector4[] destRect,
            float alpha = 1.0f,
            BlendMode backColorBlendMode = BlendMode.RealAlpha,
            XnaColor BackColor = default(XnaColor))
        {
            if (srcRect == null)
                srcRect = Pic.Bounds.ToVector4Array();

            for (int i = 0; i < 4; i++)
            {
                if (destRect == null || destRect.Length != 4)
                {
                    TempX[i] = ((srcRect[i].X) + Pos.X) - 0.5f;
                    TempY[i] = ((srcRect[i].Y) + Pos.Y) - 0.5f;
                    TempZ[i] = 1 + Pos.Z;
                }
                else
                {
                    TempX[i] = destRect[i].X - 0.5f;
                    TempY[i] = destRect[i].Y - 0.5f;
                    TempZ[i] = 1;
                }
            }
            if ((TempX[0] < 0 && TempX[1] < 0 && TempX[2] < 0 && TempX[3] < 0) ||
                (TempY[0] < 0 && TempY[1] < 0 && TempY[2] < 0 && TempY[3] < 0) ||
                (TempX[0] >= Global.Width && TempX[1] >= Global.Width && TempX[2] >= Global.Width && TempX[3] >= Global.Width) ||
               (TempY[0] >= Global.Height && TempY[1] >= Global.Height && TempY[2] >= Global.Height && TempY[3] >= Global.Height))
                return;

            if (RenderCount > 0 && ((CurTex != Pic && CurTex != null) || RenderCount >= MaxRenderCount))
                Render_Batch(Pic);
            else
            {
                if (null == CurTex || RenderCount == 0)
                {
                    CurTex = Pic;
                    Global.EftMgr.CurEffect.Parameters["Tex0"].SetValue(CurTex);
                    Global.EftMgr.CurEffect.Parameters["PicWidth"].SetValue(CurTex.Width);
                    Global.EftMgr.CurEffect.Parameters["PicHeight"].SetValue(CurTex.Height);
                }
            }
            for (int i = 0; i < 4; i++)
            {
                VertexBuf[RenderCount * 4 + i].TextureCoordinate.X = ((float)srcRect[i].X) / Pic.Width;
                VertexBuf[RenderCount * 4 + i].TextureCoordinate.Y = ((float)srcRect[i].Y) / Pic.Height;
                VertexBuf[RenderCount * 4 + i].Alpha = alpha;
                VertexBuf[RenderCount * 4 + i].UseTransparent =
                    backColorBlendMode == BlendMode.NoAlpha ? 0 : 1.0f / (float)backColorBlendMode;
                VertexBuf[RenderCount * 4 + i].BackColor = BackColor;

                VertexBuf[RenderCount * 4 + i].Position.X = TempX[i];
                VertexBuf[RenderCount * 4 + i].Position.Y = TempY[i];
                VertexBuf[RenderCount * 4 + i].Position.Z = TempZ[i];
                VertexBuf[RenderCount * 4 + i].Position.W = 1.0f;
            }
            RenderCount++;
        }
        static public void drawFrameRect(JYEvents.UIsurface.UIsurfaceType uiType)
        {
            drawFrameRect(uiType.rect.X, uiType.rect.Y, uiType.rect.Width, uiType.rect.Height);
        }
        static public void drawFrameRect(int X, int Y, int Width, int Height)
        {
            int tmpCorner = 1;//棱角大小
            RenderMgr.DrawRect(X, Y, Width, Height, 0.3f, XnaColor.Black);
            RenderMgr.DrawRect(X + tmpCorner, Y, Width -  tmpCorner, 1, 1.0f, XnaColor.White);
            RenderMgr.DrawRect(X, Y + tmpCorner, 1, Height -  tmpCorner, 1.0f, XnaColor.White);
            RenderMgr.DrawRect(X + Width, Y + tmpCorner, 1, Height -  tmpCorner, 1.0f, XnaColor.White);
            RenderMgr.DrawRect(X + tmpCorner, Y + Height, Width -  tmpCorner, 1, 1.0f, XnaColor.White);

            //RenderMgr.DrawRect(X + 1, Y + tmpCorner - 1, tmpCorner - 1, 1,1.0f,XnaColor.White);
            //RenderMgr.DrawRect(X + 1, Y + Height - tmpCorner + 1, tmpCorner - 1, 1, 1.0f, XnaColor.White);
            //RenderMgr.DrawRect(X + Width - tmpCorner + 1, Y + Height - tmpCorner + 1, tmpCorner, 1, 1.0f, XnaColor.White);
            //RenderMgr.DrawRect(X + Width - tmpCorner + 1, Y + tmpCorner - 1, tmpCorner, 1, 1.0f, XnaColor.White);

            //RenderMgr.DrawRect(X + Width - tmpCorner + 1, Y + Height - tmpCorner + 1,1,tmpCorner , 1.0f, XnaColor.White);
            //RenderMgr.DrawRect(X + Width - tmpCorner + 1, Y, 1,tmpCorner, 1.0f, XnaColor.White);

            
        }
        /// <summary>
        /// 画出在绘画队列中的纹理
        /// </summary>
        /// <param name="NextTex"></param>
        /// <param name="NextAlpha"></param>
        static public void Render_Batch(Texture2D NextTex)
        {
            if (RenderCount == 0)
                return;

            Global.EftMgr.CurEffect.Parameters["PicWidth"].SetValue(CurTex.Width);
            Global.EftMgr.CurEffect.Parameters["PicHeight"].SetValue(CurTex.Height);
            foreach (EffectPass Pass in Global.EftMgr.CurEffect.CurrentTechnique.Passes)
            {
                Pass.Apply();
                Global.XnaDevice.DrawUserIndexedPrimitives(
                     PrimitiveType.TriangleList,
                     VertexBuf,
                     0,
                     RenderCount << 2,
                     VertexIdx,
                     0,
                     RenderCount << 1,
                     vertexdec);
            }
            if (NextTex != null)
            {
                CurTex = NextTex;
                Global.EftMgr.CurEffect.Parameters["Tex0"].SetValue(NextTex);
            }
            RenderCount = 0;
        }

        static public bool IsWave = false;
        static public bool IsHole = false;
        static FontOpr GlobalFont = null;


        /// <summary>
        /// 将后台缓存画到屏幕上
        /// </summary>
        static public void ShowBuffer()
        {

            if (!IsDrawnBuffer)
            {
                switch (Global.SceneM.Statue)
                {
                    case 0:
                        {
                            Global.XnaDevice.Textures[0] = null;
                            Global.BigBuf.SetData(Global.big.drawBig(0));

                            Global.EftMgr.CurEffect.Parameters["Wave"].SetValue(IsWave ? 1 : 0);
                            Global.EftMgr.CurEffect.Parameters["Hole"].SetValue(IsHole ? 1 : 0);

                            DrawPic(
                             Global.BigBuf,
                             new Vector3(0, 0, 0),
                             Global.BigBuf.Bounds.ToVector4Array(),
                             BufRect.ToVector4Array()
                             ); 
                            IsDrawnBuffer = true;
                        }
                        break;
                    case 1:
                        {
                            Global.XnaDevice.Textures[0] = null;
                            Global.BackBuf.SetData(Global.sbuff);

                            Global.EftMgr.CurEffect.Parameters["Wave"].SetValue(IsWave ? 1 : 0);
                            Global.EftMgr.CurEffect.Parameters["Hole"].SetValue(IsHole ? 1 : 0);

                            DrawPic(
                                Global.BackBuf,
                                new Vector3(0, 0, 0),
                                MapBase.RealRect.ToVector4Array(),
                                BufRect.ToVector4Array()
                                );
                            //string asd = GlobalFont.font.Height.ToString();
                            //string sss =asd;
                            ///////////////////////////////////////////////////////////////////
                            //绘制UI层
                            ///////////////////////////////////////////////////////////////////
                            foreach (JYEvents.UIsurface.UIsurfaceType uiType in Global.uiSurface.UIlist)
                            {
                                if (uiType.Visible)
                                {
                                    switch (uiType.state)
                                    {
                                        //drawrect
                                        case 0:
                                            RenderMgr.drawFrameRect(uiType);
                                            break;
                                        //drawstring
                                        case 1:
                                            if (uiType.strColorBack != WinColor.White)
                                            {
                                                RenderMgr.DrawShadowString(uiType.strDisPlay,
                                                    new WinPoint(uiType.rect.X, uiType.rect.Y),
                                                    uiType.strColorBack, uiType.strColorFront);
                                            }
                                            else
                                            {
                                                RenderMgr.DrawString(uiType.strDisPlay,
                                                    new WinPoint(uiType.rect.X, uiType.rect.Y),
                                                    uiType.strColorFront);
                                            }
                                            break;
                                        //drawmenu
                                        case 2:
                                            int tmpLen = 0;
                                            if (uiType.UIMenu.MenuTitle != null)
                                            {
                                                tmpLen = uiType.UIMenu.MenuTitle.Length;
                                            }

                                            foreach (JYEvents.UIsurface.UIMenuStringType tmpStr in uiType.UIMenu.MenuString)
                                            {
                                                if (tmpLen < tmpStr.UiMenuString.Length) { tmpLen = tmpStr.UiMenuString.Length; }
                                            }
                                            //绘制title
                                            if (uiType.UIMenu.MenuTitle == null)
                                            {
                                                RenderMgr.drawFrameRect(uiType.UIMenu.x, uiType.UIMenu.y,
                                                    tmpLen * 20 + 10, uiType.UIMenu.MenuString.Length * 25 + 5);
                                                for (int i = 0; i < uiType.UIMenu.MenuString.Length; i++)
                                                {
                                                    if (uiType.UIMenu.SelectIndex == i)
                                                    {

                                                        RenderMgr.DrawShadowString(uiType.UIMenu.MenuString[i].UiMenuString,
                                                            new WinPoint(uiType.UIMenu.x + 5, uiType.UIMenu.y + 25 * i + 5),
                                                            WinColor.Black, WinColor.White);
                                                    }
                                                    else
                                                    {

                                                        RenderMgr.DrawShadowString(uiType.UIMenu.MenuString[i].UiMenuString,
                                                            new WinPoint(uiType.UIMenu.x + 5, uiType.UIMenu.y + 25 * i + 5),
                                                            WinColor.Brown, WinColor.Orange);
                                                    }
                                                }
                                            }
                                            else
                                            {
                                                //WinFont asd = new WinFont();

                                                RenderMgr.drawFrameRect(uiType.UIMenu.x, uiType.UIMenu.y,
                                                    20 * tmpLen + 10, (uiType.UIMenu.MenuString.Length + 1) * 25 + 5);

                                                RenderMgr.DrawShadowString(uiType.UIMenu.MenuTitle,
                                                    new WinPoint(uiType.UIMenu.x + 5, uiType.UIMenu.y + 5),
                                                    WinColor.Brown, WinColor.Yellow);

                                                for (int i = 0; i < uiType.UIMenu.MenuString.Length; i++)
                                                {
                                                    if (uiType.UIMenu.SelectIndex == i)
                                                    {

                                                        RenderMgr.DrawShadowString(uiType.UIMenu.MenuString[i].UiMenuString,
                                                            new WinPoint(uiType.UIMenu.x + 5, uiType.UIMenu.y + 25 * (i + 1) + 5),
                                                            WinColor.Black, WinColor.White);
                                                    }
                                                    else
                                                    {

                                                        RenderMgr.DrawShadowString(uiType.UIMenu.MenuString[i].UiMenuString,
                                                            new WinPoint(uiType.UIMenu.x + 5, uiType.UIMenu.y + 25 * (i + 1) + 5),
                                                            WinColor.Brown, WinColor.Orange);
                                                    }
                                                }
                                            }

                                            break;
                                        //增加头像贴图
                                        case 3:
                                            RenderMgr.DrawPic(
                                                uiType.texture,
                                                default(Vector3),
                                                null,
                                                new WinRect(uiType.Pointtexture, new WinSize((int)(uiType.texture.Width * uiType.alpha), (int)(uiType.texture.Height * uiType.alpha))).ToVector4Array(),
                                                1.0f,
                                                BlendMode.RealAlpha);
                                            break;
                                    }
                                }
                            }

                            IsDrawnBuffer = true;
                        }
                        break;
                    default:
                        break;
                }
            }
        }

        static public void DrawShadowString(string str, WinPoint pos, WinColor backcolor, WinColor frontcolor, float size = 0, string fontname = "")
        {
            DrawString(str, new WinPoint(pos.X + 1, pos.Y + 1), backcolor, false, size, fontname);
            DrawString(str, pos, frontcolor, false, size, fontname);
        }

        static public void DrawString(string str, WinPoint pos, WinColor color, bool shadow = true, float size = 0, string fontname = "")
        {
            if (size != 0 || fontname != "")
            {
                if (size == 0)
                    size = GlobalFont.font.Size;
                if (fontname != "")
                    fontname = GlobalFont.font.Name;

                GlobalFont.Reset(new WinFont(fontname, size, GraphicsUnit.Pixel));
            }
            Render_Batch(null);
            GlobalFont.DrawString(str, pos, color);

            if (shadow)
            {
                //颜色值调深就当背景色了
                WinColor backcol = WinColor.FromArgb(color.R * 2 / 3, color.G * 2 / 3, color.B * 2 / 3);
                GlobalFont.DrawString(str, new WinPoint(pos.X + 1, pos.Y + 1), backcol);
            }
            GlobalFont.DrawString(str, pos, color);
        }

        static public void DrawFog(List<FogDef> foglist)
        {
            for (int i = 0; i < foglist.Count; i++)
            {
                DrawPic(
                    foglist[i].Pic,
                    default(Vector3),
                    null,
                    new WinRect(foglist[i].Pos, new WinSize(foglist[i].Width, foglist[i].Height)).ToVector4Array(),
                    foglist[i].Alpha,
                    BlendMode.Filter);

                foglist[i].Update();
            }
        }
        static public void DrawSnow(List<SnowDef> snowlist)
        {
            for (int i = 0; i < snowlist.Count; i++)
            {
                DrawPic(
                    snowlist[i].Pic,
                    default(Vector3),
                    null,
                    new WinRect(snowlist[i].Pos, new WinSize(snowlist[i].Width, snowlist[i].Height)).ToVector4Array(),
                    snowlist[i].Alpha,
                    BlendMode.Filter);

                snowlist[i].Update();
            }
        }
        static public void DrawRain(List<RainDef> rainlist)
        {
            for (int i = 0; i < rainlist.Count; i++)
            {
                DrawPic(
                    rainlist[i].Pic,
                    default(Vector3),
                    null,
                    new WinRect(rainlist[i].Pos, new WinSize(rainlist[i].Width, rainlist[i].Height)).ToVector4Array(),
                    rainlist[i].Alpha,
                    BlendMode.Filter);

                rainlist[i].Update();
            }
        }

        static public void DrawRect(Rectangle rect, float alpha, Color col)
        {
            DrawPic(
                Global.jyWeather.RectTex,
                default(Vector3),
                null,
                rect.ToVector4Array(),
                alpha,
                BlendMode.Multi,
                col);
        }
        static public void DrawRect(int x, int y, int w, int h, float alpha, Color col)
        {
            DrawPic(
                Global.jyWeather.RectTex,
                default(Vector3),
                null,
                new Rectangle(x, y, w, h).ToVector4Array(),
                alpha,
                BlendMode.Multi,
                col);
        }
    }
    static class Expand
    {
        static public Vector4[] ToVector4Array(this Rectangle p)
        {  
            Vector4[] pt =
            {
                new Vector4(p.Left, p.Top, 1, 1),
                new Vector4(p.Right, p.Top, 1, 1),
                new Vector4(p.Right, p.Bottom, 1, 1),
                new Vector4(p.Left, p.Bottom, 1, 1)
            };
            return pt;
        }
        static public Vector4[] ToVector4Array(this WinRect p)
        {
            Vector4[] pt =
            {
                new Vector4(p.Left, p.Top, 1, 1),
                new Vector4(p.Right, p.Top, 1, 1),
                new Vector4(p.Right, p.Bottom, 1, 1),
                new Vector4(p.Left, p.Bottom, 1, 1)
            };
            return pt;
        }
    }
}